/**
 * 1. 该类位于基础设施层: infrastructure包中， 但接口定义在领域模型中domain.model.identity.AuthenticationService
 * 具体实现类在基础设施层，需要调用基础设施相关的功能来实现用户身份认证，但领域服务本身还属于领域范畴，只是实现放在基础设施层。
 * 但用户身份认证概念本身属于领域概念，因此接口定义在领域模型中。
 * 通过依赖倒置原则(DIP)，我们面对领域接口进行编程，基础设施层依赖领域层，领域层不依赖基础设施层。
 * 这点通过六边形架构或端口适配器架构可很容易理解。
 */
package com.haiya.infrastructure.services;

import com.haiya.domain.model.DomainRegistry;
import com.haiya.domain.model.identity.*;

/**
 * @author qiaoguoqiang
 */
public class DefaultEncryptionAuthenticationService implements AuthenticationService {
  public DefaultEncryptionAuthenticationService() {
    super();
  }
  
  /**
   * 2. 实现的接口方法authenticate()对参数进行基本的null检查
   */
  @Override
  public UserDescriptor authenticate(TenantId aTenantId,
                                     String aUsername,
                                     String aPassword) {
    if (aTenantId == null) {
      throw new IllegalArgumentException("TenantId must not be null.");
    }
    
    if (aUsername == null) {
      throw new IllegalArgumentException("Username must not be null.");
    }
        
    if (aPassword == null) {
      throw new IllegalArgumentException("Password must not be null.");
    }
  
  	/**
   	 * 3. 身份认证具体逻辑
   	 *    3.1 获取租户: 通过存储库查找给定的租户对象
   	 *        Tanant tanant = DomainRegistry.tenantRepository().tenantOfId(aTenantId)
   	 *    3.2 检查租户是否启用状态
   	 *        tenant.isActive()
   	 *    3.3 获取加密密码
   	 *        DomainRegistry.encryptionService().encryptedValue(aPassword)
   	 *    3.4 通过用户名和密码以及租户ID获取身份凭证
   	 *        User user =
     *           DomainRegistry.userRepository().userFromAuthenticCredentials(aTanantId, aUsername, encPass)
   	 *    3.5 判断用户凭证是否启用
   	 *           user.isEnabled()
   	 * 整个业务身份认证逻辑实现仅仅是协调各个不同业务部分，例如租户、密码加密、用户三方进行身份认证
   	 * 除此之外仅包含基本的参数null校验。
   	 * 这里领域服务任务仅仅是协调不同领域概念一起完成特定业务。
   	 */
    UserDescriptor userDescriptor = null;
    Tenant tenant = DomainRegistry.tenantRepository().tenantOfId(aTenantId);
    if (tenant != null && tenant.isActive()) {
      String encryptedPassword = DomainRegistry.encryptionService().encryptedValue(aPassword);
      User user = DomainRegistry.userRepository()
        .userFromAuthenticCredentials(aTenantId,
                                      aUsername,
                                      encryptedPassword);
      
      if (user != null && user.isEnabled()) {
        userDescriptor = user.userDescriptor();
      }
    }
    return userDescriptor;
  }
}